/*
 * ApplicationLayer.cpp
 *
 *  Created on: Mar 14, 2013
 *      Author: Xi
 */

#include "ApplicationLayer.h"
#include "TCPSocket.h"
#include "DataLinkLayer.h"
#include "Client.h"
#include <iostream>
#include<cstdlib>
#include"Client.h"
#include<sstream>
#include<vector>
#include<fstream>
#include<unistd.h>

string carrier;
vector<string> packetChunks;
int currentSeq = 0;

ApplicationLayer::ApplicationLayer() {

}

ApplicationLayer::~ApplicationLayer() {
    // TODO Auto-generated destructor stub
}

void ApplicationLayer::setCarrier(string s) {
    carrier = s;
}

/**
 * Pass orginal commands or picture to application layer, break into several packets if necessary.
 * @param cmd
 * @param port
 * @return 
 */
string ApplicationLayer::fromCmd(string cmd, int fd) {

    // debug info
    utl.echoDebugInfo("Inside Application::fromCmd()");

    // break into packets;
    string packet;
    if (cmd.length() <= 184) {
        string header = "00010001";
        packet = header + cmd;
        /*to data link layer*/
        string s = this->dl.fromAppLayer(packet, fd);
        return "a";
    } else {
        /*store them in string chunks*/
        vector<string> chunks;
        chunks = this->utl.splitString(cmd, ' ', 184);
        cout << "Divide into " << chunks.size() << " packets!" << endl;

        for (int i = 0; i < chunks.size(); i++) {

            /*add header for each chunk*/
            string header = "";
            string packet;
            stringstream ss;
            int s = chunks.size();
            ss << s;
            string lengthTemp = ss.str();
            string len = "";

            if (lengthTemp.length() < 4)
                for (int j = 0; j < (4 - lengthTemp.length()); j++)
                    len += "0";

            len += lengthTemp;
            header += len;

            packet = "";
            stringstream ss1;
            int ii = i + 1;
            ss1 << ii;
            string seqTemp = ss1.str();
            string seq = "";

            if (seqTemp.length() < 4)
                for (int j = 0; j < 4 - seqTemp.length(); j++)
                    seq += "0";

            seq += seqTemp;
            packet = header + seq + chunks.at(i);
            this->dl.fromAppLayer(packet, fd);
        }
    }
    return "a";
}

/**
 * Receive frame from data link layer and pack up to meaningful strings.
 * Handle both commands and pictures.
 * @param frame
 * @return 
 */
void ApplicationLayer::toCmd(string frame, string receiver, int fd) {

    utl.echoDebugInfo("Inside ApplicationLayer::toCmd()");
    string lengthStr = frame.substr(0, 4);
    int length = atoi(lengthStr.c_str());
    string res = frame.substr(8);

    if (carrier == "client") {
        if (length == 1) {
            /*command*/
            Client c;
            c.displayResult(res, fd);
            c.setReceivedMsg(true);
        } else {

            string seq = frame.substr(4, 4);
            int seqVal = atoi(seq.c_str());
            if (seqVal == length) {

                /*push last chunk*/

                if (seqVal == 1)
                    currentSeq = 0;
                if (seqVal - currentSeq == 1) {
                    currentSeq = seqVal;
                    cout << "Packet: " << length << " : " << seqVal << endl;

                    packetChunks.push_back(res);

                    if (length >= 10) {
                        /*file*/
                        cout << "Dumped ticket record to local file!" << endl;

                        /*pack up picture*/
                        ofstream myfile;
                        myfile.open("ticket.txt");

                        string file;
                        for (int j = 0; j < packetChunks.size(); j++) {
                            file += packetChunks[j];
                        }
                        myfile << file;
                        myfile.close();
                        packetChunks.clear();
                        Client c;
                        //  c.displayResult(file, fd);
                        c.setReceivedMsg(true);
                        cout << "Please issue a command:" << endl;
                    } else {
                        /*display result from server*/
                        res = "";
                        for (int i = 0; i < packetChunks.size(); i++) {
                            res += packetChunks[i];
                        }

                        packetChunks.clear();
                        Client c;
                        c.displayResult(res, fd);
                        c.setReceivedMsg(true);
                    }
                } else {
                    cout << "Received unexpected packet!" << endl;
                }
            } else {
                if (seqVal == 1)
                    currentSeq = 0;
                if (seqVal - currentSeq == 1) {
                    currentSeq = seqVal;
                    cout << "Packet: " << length << " : " << seqVal << endl;
                    packetChunks.push_back(res);
                } else {
                    cout << "Received unexpected packet!" << endl;
                }
            }
        }
    } else {
        TCPSocket soc;
        string backMsg = soc.parseClientCmd(res, fd);
        /*reset error rate*/
        dl.setErrorRate(-1);
        this->fromCmd(backMsg, fd);
    }
}

/**
 * Store binary file into strings then pass to data link layer
 * @param buf
 */
void ApplicationLayer::fromPic(char* buf, int fd, int size) {

    string temp(buf, size);
    /*store them in string chunks*/
    vector<string> chunks;
    chunks = this->utl.splitString(temp, ' ', 184);
    cout << "Divide  into " << chunks.size() << " packets!" << endl;

    for (int i = 0; i < chunks.size(); i++) {

        /*add header for each chunk*/
        string header = "";
        string packet;
        stringstream ss;
        int s = chunks.size();
        ss << s;
        string lengthTemp = ss.str();
        string len = "";

        if (lengthTemp.length() < 4)
            for (int j = 0; j < (4 - lengthTemp.length()); j++)
                len += "0";

        len += lengthTemp;
        header += len;

        packet = "";
        stringstream ss1;
        int ii = i + 1;
        ss1 << ii;
        string seqTemp = ss1.str();
        string seq = "";

        if (seqTemp.length() < 4)
            for (int j = 0; j < 4 - seqTemp.length(); j++)
                seq += "0";

        seq += seqTemp;
        packet = header + seq + chunks.at(i);
        this->dl.fromAppLayer(packet, fd);
    }
}

